package sanshui.system.trade.factory.trade.worker;

import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sanshui.system.trade.common.GlobalContain;
import sanshui.system.trade.db.mapper.StockATradeCalMapper;
import sanshui.system.trade.factory.data.DataCache;
import sanshui.system.trade.factory.data.DataMarketType;
import sanshui.system.trade.factory.data.TradeMarketKey;
import sanshui.system.trade.factory.data.TradeSystemType;
import sanshui.system.trade.factory.notify.TradeSysNotify;
import sanshui.system.trade.factory.notify.TradeSysNotifyModel;
import sanshui.system.trade.factory.trade.TradeSystemContext;
import sanshui.system.trade.factory.trade.strategy.StrategyResult;
import sanshui.system.trade.factory.trade.strategy.TradeStrategy;
import sanshui.system.trade.model.NotifyModel;
import sanshui.system.trade.model.TradeSysWorkerModel;
import sanshui.system.trade.util.CommonTimeUtil;

import java.time.LocalDateTime;
import java.util.List;

public abstract class RtTradeWorker extends AbstractTradeWorker {
    private static final Logger logger = LoggerFactory.getLogger(RtTradeWorker.class);


    public RtTradeWorker(TradeSysWorkerModel tradeModel, DataCache dataCache) {
        super(tradeModel, dataCache);
    }

    protected abstract boolean isValidInThisAccountUseCache(List<StrategyResult> endStrategyCalls) throws Exception;

    @Override
    protected void notifyInfo(TradeSystemContext context, GlobalContain.NotifyType notifyType) {
        if (notifyType.compareTo(GlobalContain.NotifyType.BS_SINGLE) == 0) {
            LocalDateTime current = context.getTimeManager().timestampCurrent;
            if (CommonTimeUtil.getNowTime8().equalsIgnoreCase(CommonTimeUtil.getNowTime8(current))){
                TradeSysNotifyModel notifyModel = new TradeSysNotifyModel();
                TradeSysNotify notifyImpl = notifyService.getNotifyService(context.getNotifyChannel().name());

                notifyModel.setTitle(Strings.isEmpty(context.getAccount().getAccDesc())? "量化通知": context.getAccount().getAccDesc());
                String orgContents = notifyImpl.buildContents(context.getStrategyResults(), notifyType);
                notifyModel.setOriContent(orgContents);
                if (!Strings.isEmpty(orgContents)){
                    logger.info("发起通知, workerId:{}, notifyType:{}", context.getWorkerId(), notifyType);
                    logger.info("构建通知model，执行内容:{}", orgContents);
                    notifyImpl.execute(notifyModel);
                }
            }
        }

        if (notifyType.compareTo(GlobalContain.NotifyType.TRADE) == 0) {
            LocalDateTime current = context.getTimeManager().timestampCurrent;
            if (CommonTimeUtil.getNowTime8().equalsIgnoreCase(CommonTimeUtil.getNowTime8(current))){
                logger.info("发起通知, workerId:{}, notifyType:{}", context.getWorkerId(), notifyType);

            }
        }

    }

    protected void updateAccountToCacheInRt(){
        logger.info("实时更新账户信息到缓存中..., workerId:{}", tradeSystemContext.getWorkerId());

    }

    @Override
    protected boolean isWeek(LocalDateTime currentTime) throws Exception {
        if (null == currentTime){
            return false;
        }
        return dataFactory.isWeekend(currentTime);
    }

    @Override
    protected boolean needWaitData(LocalDateTime currentTime) throws Exception {
        if (null == currentTime){
            long millisNeed = this.tradeModel.getMillis() < 5000L ? 5000L: this.tradeModel.getMillis();
            logger.warn("还未出现下一个驱动时间，睡眠等待, 睡眠时间:{}毫秒, currentTime:{}", millisNeed, CommonTimeUtil.getNowTime16(currentTime));
            this.sleep(millisNeed);
            return true;
        }
        // 实时系统很可能在睡眠时间内无法拿到所有目标的数据
        String exeTime4ForT1 = this.tradeModel.getExeTime4ForT1();
        boolean isBeforExe = false;
        if (Strings.isNotEmpty(exeTime4ForT1)){
            LocalDateTime exeDate = CommonTimeUtil.getDate(currentTime,
                    exeTime4ForT1.substring(0, 2),
                    exeTime4ForT1.substring(2, 4),
                    exeTime4ForT1.substring(4, 6));
            if (currentTime.isBefore(exeDate)){
                isBeforExe = true;
            }
        }

        // 查询实时数据
        boolean notGet = dataCache.updateInRtWait(currentTime, this::parseOri2Tick);
        if (notGet) {
//            if (dataCache.isWeekend(currentTime) && TradeMarketKey.A_GU.compareTo(this.tradeMarketKey) == 0) {
//                logger.warn("A股当前时间是周末，睡眠等待, 睡眠时间:{}毫秒, currentTime:{}, 自定义执行时间:{}", this.tradeModel.getMillis(), CommonTimeUtil.getNowTime16(currentTime), exeTime4ForT1);
//                timeManager.pollNext();
//                this.sleep(this.tradeModel.getMillis() < 5000L ? 5000L: this.tradeModel.getMillis());
//                return true;
//            }
            if (isBeforExe){
                return true;
            }
            logger.warn("当前时间没有命中数据，睡眠等待, 睡眠时间:{}毫秒, currentTime:{}, 自定义执行时间:{}", this.tradeModel.getMillis(), CommonTimeUtil.getNowTime16(currentTime), exeTime4ForT1);
            this.sleep(this.tradeModel.getMillis() < 5000L ? 5000L: this.tradeModel.getMillis());
            return true;
        }
        return false;
    }

    @Override
    protected boolean continueTradeClear(LocalDateTime currentTime, DataCache dataCache) {
        if (null == currentTime) {
            // 清除历史数据, 清理空间
            dataCache.clear();
            logger.debug("交易中历史数据已经用完了, 开始等待下一次命中, now:{}", CommonTimeUtil.getNowTime16(LocalDateTime.now()));
            return true;
        }
        return true;
    }

}
